/*******************************************************************************
 * Copyright (c) 2000, 2003 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Common Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/cpl-v10.html
 * 
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
module dwt.dnd.filetransfer;


private import dwt.dwt;

private import dwt.dnd.bytearraytransfer;
private import dwt.dnd.transferdata;
private import dwt.internal.ole.win32.com;
private import dwt.internal.ole.win32.OBJIDL;


alias ArbitraryObj!(char[][]) StringArrayObj;

/**
 * The class <code>FileTransfer</code> provides a platform specific mechanism 
 * for converting a list of files represented as a java <code>String[]</code> to a 
 * platform specific representation of the data and vice versa.  
 * Each <code>String</code> in the array contains the absolute path for a single 
 * file or directory.
 * See <code>Transfer</code> for additional information.
 * 
 * <p>An example of a java <code>String[]</code> containing a list of files is shown 
 * below:</p>
 * 
 * <code><pre>
 *     File file1 = new File("C:\temp\file1");
 *     File file2 = new File("C:\temp\file2");
 *     String[] fileData = new String[2];
 *     fileData[0] = file1.getAbsolutePath();
 *     fileData[1] = file2.getAbsolutePath();
 * </code></pre>
 */
public class FileTransfer : ByteArrayTransfer {

	private import std.c.windows.windows;

	
	private static FileTransfer _instance;
	private static char[] CF_HDROP = "CF_HDROP ";
	private static const int CF_HDROPID = COM.CF_HDROP;
	private static char[] CF_HDROP_SEPARATOR = "\0";
	
	private static boolean staticCtor_done = false;
private this() {
	if(!staticCtor_done) {
		staticCtor_done = true;
		_instance = new FileTransfer();
	}
}

/**
 * Returns the singleton instance of the FileTransfer class.
 *
 * @return the singleton instance of the FileTransfer class
 */
public static FileTransfer getInstance () {
	return _instance;
}

/**
 * This implementation of <code>javaToNative</code> converts a list of file names
 * represented by a java <code>String[]</code> to a platform specific representation.
 * Each <code>String</code> in the array contains the absolute path for a single 
 * file or directory.  For additional information see 
 * <code>Transfer#javaToNative</code>.
 * 
 * @param object a java <code>String[]</code> containing the file names to be 
 * converted
 * @param transferData an empty <code>TransferData</code> object; this
 *  object will be filled in on return with the platform specific format of the data
 */

/// \param object an ArbitraryObj!(char[][]) Object
public void javaToNative(Object object, TransferData transferData) {
	transferData.result = COM.E_FAIL;
	if (object is null)	return;

	StringArrayObj artObj = cast(StringArrayObj)object;
	if (artObj is null || artObj.data is null) return;
	
	if (!isSupportedType(transferData)) {
		// did not match the TYMED
		transferData.stgmedium = new STGMEDIUM();
		transferData.result = COM.DV_E_TYMED;
		return;
	}

	char[][] fileNames = cast(char[][])artObj.data;
	char[] allFiles;
	for (int i = 0; i < fileNames.length; i++) {
		allFiles ~= (fileNames[i]); 
		allFiles ~= (CF_HDROP_SEPARATOR); // each name is null terminated
	}
	char[] buffer = allFiles ~ CF_HDROP_SEPARATOR; // there is an extra null terminator at the very end
	DROPFILES* dropfiles = new DROPFILES();
	dropfiles.pFiles = DROPFILES.sizeof;
	dropfiles.pt.x = dropfiles.pt.y = 0;
	dropfiles.fNC = 0;
	dropfiles.fWide = COM.IsUnicode ? 1 : 0;
	// Allocate the memory because the caller (DropTarget) has not handed it in
	// The caller of this method must release the data when it is done with it.
	
	TCHAR* pbuf = Converter.StrToTCHARz(buffer);
	int byteCount = tango.stdc.string.strlen(cast(char*)pbuf);
	HGLOBAL newPtr = COM.GlobalAlloc(COM.GMEM_FIXED | COM.GMEM_ZEROINIT, DROPFILES.sizeof + byteCount);
	OS.MoveMemory(newPtr, dropfiles, DROPFILES.sizeof);
	OS.MoveMemory(newPtr + DROPFILES.sizeof, pbuf, byteCount);
	transferData.stgmedium = new STGMEDIUM();
	transferData.stgmedium.tymed = COM.TYMED_HGLOBAL;
	transferData.stgmedium.unionField = newPtr;
	transferData.stgmedium.pUnkForRelease = null;
	transferData.result = COM.S_OK;
}
/**
 * This implementation of <code>nativeToJava</code> converts a platform specific 
 * representation of a list of file names to a java <code>String[]</code>.  
 * Each String in the array contains the absolute path for a single file or directory. 
 * For additional information see <code>Transfer#nativeToJava</code>.
 * 
 * @param transferData the platform specific representation of the data to be 
 * been converted
 * @return a java <code>String[]</code> containing a list of file names if the 
 * conversion was successful; otherwise null
 */
public Object nativeToJava(TransferData transferData) {
	if (!isSupportedType(transferData) || transferData.pIDataObject is null)  return null;
	
	// get file names from _IDataObject
	IDataObject dataObject = transferData.pIDataObject;
	dataObject.AddRef();
	FORMATETC* formatetc = new FORMATETC();
	formatetc.cfFormat = COM.CF_HDROP;
	formatetc.ptd = null;
	formatetc.dwAspect = COM.DVASPECT_CONTENT;
	formatetc.lindex = -1;
	formatetc.tymed = COM.TYMED_HGLOBAL;
	STGMEDIUM* stgmedium = new STGMEDIUM();
	stgmedium.tymed = COM.TYMED_HGLOBAL;
	transferData.result = dataObject.GetData(formatetc, stgmedium);
	dataObject.Release();
	if (transferData.result != COM.S_OK) return null;
	// How many files are there?
	int count = COM.DragQueryFile(cast(HDROP)stgmedium.unionField, 0xFFFFFFFF, null, 0);
	char[][] fileNames = new char[][count];
	for (int i = 0; i < count; i++) {
		// How long is the name ?
		int size = COM.DragQueryFile(cast(HDROP)stgmedium.unionField, i, null, 0) + 1;
		TCHAR[] lpszFile = new TCHAR[size];	
		// Get file name and append it to string
		COM.DragQueryFile(cast(HDROP)stgmedium.unionField, i, lpszFile.ptr, size);
		fileNames[i] = Converter.TCHARzToStr(lpszFile.ptr);
	}
	COM.DragFinish(cast(HDROP)stgmedium.unionField); // frees data associated with HDROP data
	
	StringArrayObj object = new StringArrayObj(fileNames); 
	return object;
}

protected int[] getTypeIds(){
	int[] intArr;
	intArr ~= CF_HDROPID;
	return intArr;
}

protected char[][] getTypeNames(){
	char[][] StringArr;
	StringArr ~= (CF_HDROP);
	return StringArr;
}

boolean checkFile(Object object) {
	if(object is null  || cast(StringArrayObj)object is null || (cast(StringArrayObj)object).data.length == 0)
		return false;
	char[][] strings = (cast(StringArrayObj)object).data;
	for (int i = 0; i < strings.length; i++) {
		if (strings[i] is null || strings[i].length == 0) return false;
	}
	return true;
}

boolean validate(Object object) {
	return checkFile(object);
}

}
